package ru.ipo.dces.plugins;

import java.applet.Applet;
import java.applet.AppletContext;
import java.applet.AudioClip;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.*;

import ru.ipo.dces.exceptions.GeneralRequestFailureException;
import ru.ipo.dces.pluginapi.PluginEnvironment;
import ru.ipo.dces.utils.FileSystemUtils;
import ru.ipo.problemsapi.ExtendedProblem;
import sun.plugin.javascript.JSContext;
import netscape.javascript.JSObject;


public class MathkitApplet extends JPanel implements Runnable, AppletContext, JSContext {

    Thread t;
    JApplet myApplet = null;
    MyAppletStub myStub = null;
    //JFrame frame;
    //String path;
    DCESJSObject obj = new DCESJSObject();
    PluginEnvironment e;
    HashMap<String, String> solution = new HashMap<String, String>();


    class DCESJSObject extends JSObject {

        public Object getMember(String name) {
            return new Object();
        }

        public Object getSlot(int index) {
            return new Object();
        }

        public void setMember(String name, Object value) {
        }

        public void setSlot(int index, Object value) {
        }

        public void removeMember(String name) {
        }

        public Object call(String methodName, Object args[]) {
            return new Object();
        }

        public Object eval(String s) {
            int i = s.indexOf("(");
            String m = s.substring(0, i);
            char args[] = new char[s.length() - i];
            String arg1 = "", arg2 = "";

            s.getChars(i, s.length(), args, 0);

            for (char arg : args) {
                if (arg != '(' && arg != ')') {
                    if (arg == ',') {
                        arg1 = arg2;
                        arg2 = "";
                    } else {
                        arg2 = arg2 + arg;
                    }
                }
            }
            arg1 = arg1.trim();
            arg2 = arg2.trim();
            if (arg1.endsWith("'") && arg1.startsWith("'"))
                arg1 = arg1.substring(1, arg1.length() - 1);
            if (arg2.endsWith("'") && arg2.startsWith("'"))
                arg2 = arg2.substring(1, arg2.length() - 1);
            if (m.equals("SCORM.setDataValue")) {
                solution.put(arg1, arg2);

            } else if (m.equals("SCORM.commitData")) {
                submitSolutionWithConfirmation(solution);
                solution = new HashMap<String, String>();
            }
            return new Object();
        }

    }

    private void submitSolutionWithConfirmation(HashMap<String, String> solution) {
        //if testanswer is set, then plugins needs to send text answer and we should test if it is long enough
        String textAnswer = solution.get("textanswer");
        if (textAnswer != null)
            if (!testTextAnswer(textAnswer)) return;

        //test selection count
        String needSelect = solution.get("need_select");
        String selected = solution.get("selected");
        if (needSelect != null && selected != null)
            if (!selected.equals(needSelect)) {
                JOptionPane.showMessageDialog(
                        this,
                        "Выберите " + needSelect + " " +
                                rus(Integer.parseInt(needSelect), "объект", "", "а", "ов") +
                                " и повторите отсылку решения"
                );
                return;
            }

        solution.remove("need_select");
        solution.remove("selected");

        if (JOptionPane.showConfirmDialog(this, "Подтвердите отсылку решения") != JOptionPane.YES_OPTION)
            return;

        try {
            e.submitSolution(solution);
            JOptionPane.showMessageDialog(this, "Решение удачно отослано");
        } catch (GeneralRequestFailureException e) {
            JOptionPane.showMessageDialog(this, "Решение не послано всвязи с проблемами со связью");
        }
    }

    private String rus(int val, String noun, String sing, String dbl, String mult) {
        int last = val % 10;
        int prev = val / 10 % 10;

        if (prev == 1)
            return noun + mult;
        else if (last == 1)
            return noun + sing;
        else if (last >= 2 && last <= 4)
            return noun + dbl;
        else
            return noun + mult;
    }

    private boolean testTextAnswer(String textAnswer) {
        textAnswer = textAnswer.trim();

        if (textAnswer.equals("")) {
            JOptionPane.showMessageDialog(this, "Введите пояснение к вашему решению.");
            return false;
        }

        if (textAnswer.length() < 6) {
            JOptionPane.showMessageDialog(this, "Ваше пояснение к решению слишком короткое.\nВведите более подробное пояснение и повторите отсылку решения.");
            return false;
        }
        return true;
    }

    public void setPathApplet() throws IOException {
        try {
            Class<?> c;
            e = PluginInt.pe;
            File APPLET_ROOT = unpackTemporary(e.getProblem());
            AppletParameters ap = new AppletParameters(APPLET_ROOT);

            c = Class.forName("rus.sketchpad.gui.SketchpadApplet");
            myApplet = (JApplet) c.newInstance();
            myStub = new MyAppletStub(myApplet, MathkitApplet.this, ap.parameters());
            myApplet.setStub(myStub);

            t = new Thread() {
                public void run() {
                    myApplet.init();
                    myApplet.start();
                }
            };

            setLayout(new BorderLayout());
            add(myApplet, BorderLayout.CENTER);
            t.start();
        } catch (MalformedURLException ex) {
            Logger.getLogger(MathkitApplet.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(MathkitApplet.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            Logger.getLogger(MathkitApplet.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(MathkitApplet.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private File unpackTemporary(ExtendedProblem problem) throws IOException {
        File f = File.createTempFile("mathkit-problem", ".problem.unzip");
        f.delete();
        f.mkdirs();
        f.deleteOnExit();

        File appletSettings = new File(f.getPath() + "/applet-settings.xml");
        appletSettings.deleteOnExit();
        FileSystemUtils.copyFileFromInputStream(
                problem.getReadStream("applet-settings.xml"),
                appletSettings
        );

        File statement = new File(f.getPath() + "/statement.mkz");
        statement.deleteOnExit();
        FileSystemUtils.copyFileFromInputStream(
                problem.getReadStream("statement.mkz"),
                statement
        );

        return f;
    }

    public void showStatus(String s) {
    }

    public AudioClip getAudioClip(URL url) {
        return null;
    }

    public Image getImage(URL url) {
        return Toolkit.getDefaultToolkit().createImage(url);
    }

    public Applet getApplet(String name) {
        return null;
    }

    @SuppressWarnings("unchecked")
    public Enumeration getApplets() {
        return null;
    }

    public void showDocument(URL url) {
    }

    public void showDocument(URL url, String target) {
    }

    public void setStream(String key, InputStream stream) throws IOException {

    }

    public InputStream getStream(String key) {
        return null;
    }

    public Iterator<String> getStreamKeys() {
        return null;
    }

    public void run() {
    }

    public JSObject getJSObject() {
        return obj;
    }

    public JSObject getOneWayJSObject() {
        return null;
    }
}
